package tr.helper.controller.home;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import io.vavr.Tuple3;
import java.io.File;
import java.math.BigDecimal;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
import javafx.util.Pair;
import lombok.var;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.nodes.Element;
import tr.helper.CommonUtil;
import tr.helper.UserHolder;
import tr.helper.controller.Context;
import tr.helper.controller.SecurityController;
import tr.helper.controller.log.LogController;
import tr.helper.controller.user.UserAddController;
import tr.helper.domain.DataConfig;
import tr.helper.repository.table.User;
import tr.helper.service.TrService;
import tr.helper.view.DetailItem;
import tr.helper.view.TradeItem;
import tr.helper.view.UserItem;

public class HomeController extends SecurityController {

    private static boolean forceLogin = false;

    @FXML
    private Button btnCache;

    @FXML
    private ProgressBar progressBar;

    @FXML
    private TableView<DetailItem> listDetails;

    @FXML
    private TableView<UserItem> selectUsers;

    @FXML
    private TableView<TradeItem> tblItems;

    @FXML
    private ChoiceBox<Pair<String, Long>> boxChoice;

    @FXML
    private TextField txtServerHost;

    @FXML
    private Button btnPull;

    @FXML
    private Label lbMsg;

    @FXML
    private Label lbMsg2;

    public Stage userStage = null;

    public Stage logStage = null;

    public void putUsers(ObservableList<UserItem> users) {
        selectUsers.getColumns().clear();
        selectUsers.getColumns().addAll(CommonUtil.getTableCols(UserItem.class));
        selectUsers.getItems().clear();
        selectUsers.getItems().addAll(users);
    }

    @Override
    public void init(URL location, ResourceBundle resources) {
        tblItems.getColumns().clear();
        tblItems.getColumns().addAll(CommonUtil.getTableCols(TradeItem.class));
        DataConfig.initMasters(boxChoice);
        progressBar.setVisible(false);
        progressBar.setProgress(0);
        progressBar.setPrefWidth(1300);
    }

    @FXML
    public void doAdd() throws Exception {
        AnchorPane userPane = FXMLLoader.load(CommonUtil.getFxmlResource("user/UserAddForm.fxml"));
        if (null != userStage) {
            userStage.close();
            userStage = null;
        }
        userStage = new Stage();
        userStage.setScene(new Scene(userPane));
        userStage.setTitle("选择用户");
        userStage.show();

        UserAddController userAddController = (UserAddController) Context.controllers.get(UserAddController.class.getSimpleName());
        Pair<String, Long> pair = boxChoice.getValue();
        userAddController.boxChoice.setValue(pair);
    }

    @FXML
    public void doGetUser() throws Exception {
        AnchorPane pane = FXMLLoader.load(CommonUtil.getFxmlResource("user/UserListForm.fxml"));
        if (null != userStage) {
            userStage.close();
            userStage = null;
        }
        userStage = new Stage();
        userStage.setScene(new Scene(pane));
        userStage.setTitle("辅助中心 欢迎你:" + UserHolder.getInstance().getUser().getUsername());
        userStage.show();
    }

    @FXML
    public void doOpenLog() throws Exception {
        AnchorPane pane = FXMLLoader.load(CommonUtil.getFxmlResource("log/LogForm.fxml"));
        if (null != logStage) {
            logStage.close();
            logStage = null;
        }
        logStage = new Stage();
        logStage.setScene(new Scene(pane));
        logStage.setTitle("操作日志");
        logStage.show();
    }

    @FXML
    public void doInitData() {
        forceLogin = !forceLogin;
        if (forceLogin) {
            btnCache.setText("强制登录");
        } else {
            btnCache.setText("缓存登录");
        }
    }

    @FXML
    public void doCancel() throws Exception {
        ObservableList<TradeItem> list = tblItems.getSelectionModel().getSelectedItems();
        if (CollectionUtil.isEmpty(list)) {
            CommonUtil.alert(null, "请先选择要取消托管的账号");
            return;
        }
        HomeController home = (HomeController) Context.controllers.get(HomeController.class.getSimpleName());
        home.doOpenLog();
        LogController log = (LogController) Context.controllers.get(LogController.class.getSimpleName());
        log.doClear();
        for (TradeItem tradeItem : list) {
            User condUser = new User();
            condUser.setId(tradeItem.getUserId());
            User user = userDao.select(condUser);
            HttpResponse response = trService.cancel(user.getCookie(), user.getToken(), user.getPassword(), tradeItem.getId());
            log.addLog(JSON.parseObject(response.body()).getString("showTittle"));
        }
    }

    /**
     * 拉取交易信息
     *
     * @throws Exception
     */
    @FXML
    public void doPull() throws Exception {
        // 准备用户信息
        if (CollectionUtil.isEmpty(selectUsers.getItems())) {
            CommonUtil.alert(null, "请先选择要查看的用户");
            return;
        }
        LogController log = (LogController) Context.controllers.get(LogController.class.getSimpleName());
        if (null == log) {
            doOpenLog();
            log = (LogController) Context.controllers.get(LogController.class.getSimpleName());
        }
        final LogController logController = log;
        progressBar.setVisible(true);
        Service<Double> service = new Service<Double>() {
            @Override
            protected Task<Double> createTask() {
                return new Task<Double>() {
                    @Override
                    protected Double call() {
                        super.updateProgress(0, 1280);
                        begin(logController, v -> {
                            super.updateProgress(v, 1280);
                        });
                        super.updateProgress(1280, 1280);
                        Platform.runLater(() -> {
                            progressBar.setVisible(false);
                        });
                        return null;
                    }
                };
            }
        };
        progressBar.progressProperty().bind(service.progressProperty());
        Platform.runLater(service::restart);
    }

    static int countWin;
    static int countLose;
    static List<Map<String, Object>> details;

    private void begin(LogController log, Consumer<Double> consumer) {
        details = new ArrayList<>();
        countWin = 0;
        countLose = 0;
        BigDecimal b = new BigDecimal(1300 / selectUsers.getItems().size());
        double avgVal = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        final TrService trService = new TrService(txtServerHost.getText());
        try {
            btnPull.setDisable(true);

            File file = new File(CommonUtil.getHomeImagePath());
            FileUtil.mkdir(file);
            tblItems.getItems().clear();
            double progressValue = 0;
            for (UserItem user : selectUsers.getItems()) {
                double arriveValue = BigDecimal.valueOf(avgVal / 4).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                progressValue += arriveValue;
                consumer.accept(progressValue);
                log.doClear();
                Tuple3<HttpResponse, String, String> tuple3 = getCookie(user, log, forceLogin);
                progressValue += arriveValue;
                consumer.accept(progressValue);

                // 抓取交易数据
                getFunds(log, trService, user, tuple3._3(), tuple3._1(), tuple3._2());
                progressValue += arriveValue;
                consumer.accept(progressValue);

                // 抓取余额
                getBalance(log, trService, user, tuple3._3(), tuple3._1(), tuple3._2());
                progressValue += arriveValue;
                consumer.accept(progressValue);
            }
            if (file.exists()) {
                log.addLog("清空缓存验证码图片%s张", FileUtil.listFileNames(file.getPath()).size());
                FileUtil.del(file);
            }
            btnPull.setDisable(false);

            int curWeek = CommonUtil.getWeek(new SimpleDateFormat("yyyy-MM-dd ").format(new Date()));
            int tradingCount = 0;
            int failedCount = 0;
            int waitCount = 0;
            int winCount = 0;
            BigDecimal totalAmount = BigDecimal.ZERO;
            for (TradeItem tradeItem : tblItems.getItems()) {
                totalAmount = totalAmount.add(CommonUtil.getBalance(tradeItem.getBalanceA()));
                totalAmount = totalAmount.add(CommonUtil.getBalance(tradeItem.getBalanceB()));
                // 一次都没交易过的
                if (StringUtils.isBlank(tradeItem.getTradeDate()) || StringUtils.contains(tradeItem.getStatus(), "可以交易")) {
                    waitCount += 1;

                    if (!StringUtils.startsWith(tradeItem.getGainA(), "-")) {
                        winCount += 1;
                    }
                    if (StringUtils.startsWith(tradeItem.getGainA(), "-")) {
                        failedCount += 1;
                    }
                    continue;
                }
                if (StringUtils.contains(tradeItem.getStatus(), "交易中")) {
                    tradingCount += 1;
                } else if (StringUtils.contains(tradeItem.getStatus(), "保险") || StringUtils.startsWith(tradeItem.getGainA(), "-")) {
                    failedCount += 1;
                } else if (StringUtils.contains(tradeItem.getStatus(), "盈利") || !StringUtils.startsWith(tradeItem.getGainA(), "-")) {
                    winCount += 1;
                }
            }
            int finalWinCount = winCount;
            int finalFailedCount = failedCount;
            int finalWaitCount = waitCount;
            int finalTradingCount = tradingCount;
            final BigDecimal sumAmount = totalAmount;
            Platform.runLater(() -> {
                if (CollectionUtil.isNotEmpty(details)) {
                    Map<String, List<Map<String, Object>>> detailsGroup = details.stream().collect(Collectors.groupingBy(d -> d.get("month").toString()));
                    List<DetailItem> detailItems = Lists.newArrayList();
                    detailsGroup.forEach((m, d) -> {
                        DetailItem item = new DetailItem();
                        item.setMonth(m);
                        Integer win = d.stream().map(a -> Integer.valueOf(CommonUtil.asString(a.get("win")))).reduce(Integer::sum).get();
                        Integer lose = d.stream().map(a -> Integer.valueOf(CommonUtil.asString(a.get("lose")))).reduce(Integer::sum).get();
                        item.setWin(win);
                        item.setLose(lose);
                        detailItems.add(item);
                    });
                    listDetails.getColumns().clear();
                    listDetails.getColumns().addAll(CommonUtil.getTableCols(DetailItem.class));
                    listDetails.getItems().clear();
                    listDetails.getItems().addAll(detailItems);
                }

                lbMsg.setText(String.format("盈利:%s 亏损:%s 待交易:%s 交易中:%s", finalWinCount, finalFailedCount, finalWaitCount, finalTradingCount));
                lbMsg2.setText(String.format("总胜:%s, 总负:%s 总投:%s", countWin, countLose, sumAmount));
                logStage.close();
            });
        } catch (Exception e) {
            log.addLog("拉取账号:%s的交易信息失败", e.getMessage());
            btnPull.setDisable(false);
        }
    }

    private void getBalance(LogController log, TrService trService, UserItem user, String cookies, HttpResponse csResponse, String token) {
        try {
            Element doc = trService.getBalance(cookies);
            String strBalanceW = doc.getElementsByClass("balanceW").get(0).text();
            String strBalanceU = doc.getElementsByClass("balanceU").get(0).text();
            User updUser = new User();
            updUser.setBalanceU(CommonUtil.getBalance(strBalanceU));
            updUser.setBalanceW(CommonUtil.getBalance(strBalanceW));
            userDao.updateByPrimaryKey(updUser, user.getId());
            log.addLog("拉取账号:%s钱包并更新成功 W:%s U:%s", user.getUsername(), strBalanceW, strBalanceU);
        } catch (Exception e) {
            log.addLog("拉取账号:%s钱包并更新失败 原因:%s", user.getUsername(), e.getMessage());
        }
    }

    private void getFunds(LogController log, TrService trService, UserItem user, String cookies, HttpResponse csResponse, String token) {
        try {
            HttpResponse response = trService.getFunds(cookies);
            if (response.getStatus() == 200) {
                JSONObject jsonObject = JSON.parseObject(response.body());
                JSONArray array = jsonObject.getJSONArray("data");
                for (int i = 0; i < array.size(); i++) {
                    JSONObject fundData = array.getJSONObject(i);
                    if (StringUtils.isBlank(fundData.getString("fundcompany"))) {
                        continue;
                    }
                    JSONObject history = trService.getHistory(cookies, fundData.getLong("bookA"));

                    final var ds = (List<Map<String, Object>>) history.get("details");

                    StringBuilder remark = new StringBuilder();
                    if (CollectionUtil.isNotEmpty(ds)) {
                        details.addAll(ds);
                        for (Map<String, Object> detail : ds) {
                            remark.append(String.format("【%s月 %s +%s -%s】", detail.get("month"), CommonUtil.sub(detail.get("trade").toString(), 4), detail.get("win"), detail.get("lose")));
                        }
                    }
                    String sales = fundData.getString("sales");
                    TradeItem tradeItem = new TradeItem(user.getUsername(), user.getId(), user.getMaster(), fundData.getLong("bookA"), fundData.getString("fundcompany"),
                        fundData.getString("balanceA"), fundData.getString("balanceB"),
                        fundData.getString("status"), fundData.getString("txndate"),
                        fundData.getString("bookAwin") + StringUtils.replace(sales, "<br><span style=\"color:red;\">", "").replace("<span>", ""), fundData.getString("fundcompany"),
                        history.getString("win"), history.getString("lose"), CommonUtil.trimEnd(remark.toString(), "> "));

                    tblItems.getItems().add(tradeItem);
                    countWin += history.getIntValue("win");
                    countLose += history.getIntValue("lose");
                }
            } else {
                if (response.body().contains("/chs/settings/account")) {
                    log.addLog("拉取账号:%s的交易信息失败 http状态码:%s 请先重置密码!", user.getUsername(), response.getStatus());
                } else {
                    log.addLog("拉取账号:%s的交易信息失败 http状态码:%s 可能令牌失效!", user.getUsername(), response.getStatus());
                    //String newCookie = autoLogin(log, trService, user, cookies, csResponse, token);
                    //getFunds(log, trService, user, newCookie, csResponse, token);
                }
            }
        } catch (Exception e) {
            log.addLog("拉取账号:%s的交易信息失败 原因:%s", user.getUsername(), e.getMessage());
            log.addLog("开始重新拉取账号:%s的交易信息", user.getUsername());
            CommonUtil.sleep(500L);
            getFunds(log, trService, user, cookies, csResponse, token);
        }
    }

}
